/*
 * FC_Topology.c
 *
 *  Created on: Dec 12, 2011
 *      Author: B37531
 */
#include "drive.h"
#include "FC_protocol.h"

/********************************************************************/
////////////////////////////////////////////////////
// variable declare
u16 uiNumberCount = 0;
u8  g_ucFC_State;
static u8 m_uiRecCount;
static u8 *m_pRecFrame;
static u8  m_ucDataBuff[WRITE_BLOCK_SIZE];
static REC_FRAME_HEAD  m_RecFrame;

const FC_IDENT_INFO m_MCU_Info =
{
    FC_PROTOCOL_VERSION,
    IDENT_SDID,
    FLASH_NUM,
    USER_FLASH_START_ADDR,
    USER_FLASH_END_ADDR,
    RELOCATION_VERTOR_ADDR,
    INTERRUPT_VERTOR_ADDR,
    ERASE_BLOCK_SIZE,
    WRITE_BLOCK_SIZE,
    K15_STRING
};

/*****************************************************************************//*!
+FUNCTION----------------------------------------------------------------
* @function name: FC_Init
*
* @brief Initialize Flash  and valiable
*
* @param
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/


void FC_Init(void)
{
//  Flash_Init();
    FLASH_Init(BUS_CLK_HZ);
    m_pRecFrame  = (u8 *)&m_RecFrame;
    g_ucFC_State = FC_STATE_NULL;
    m_uiRecCount = 0;
}
/*****************************************************************************//*!
+FUNCTION----------------------------------------------------------------
* @function name: UART_Send
*
* @brief send data by uart
*
* @param
*           pData - first address of transmitting data
*           uiSize - length
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/

void UART_Send(u8 *pData,u16 uiSize)
{
    unsigned int i;
    for(i=0; i<uiSize; i++)
    {
        UART_PutChar(TERM_PORT,pData[i]);
    }
}

/*****************************************************************************//*!
+FUNCTION----------------------------------------------------------------
* @function name: FC_Communication
*
* @brief hadle FC protocol with PC tools
*
* @param
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/

u8 FC_Communication(void)
{
    u8 uiReadData,i;
    u8 *pAddress;
    ADDRESS_TYPE * pTempAddress;
    if(UART_S1_RDRF_MASK != UART_CharPresent(TERM_PORT))
    {
        return 0;
    }

    // read data from uart
    uiReadData = UART_GetChar(TERM_PORT);
    switch(g_ucFC_State)
    {
        case FC_STATE_NULL:
        {
            if(uiReadData == FC_CMD_ACK)
            {
                UART_PutChar(TERM_PORT,0xfc);
                g_ucFC_State = FC_STATE_WORKING;
            }
            else
            {
                return 0;
            }
        }
        break;
        case FC_STATE_WORKING:
        {
            switch(uiReadData)
            {
                case FC_CMD_IDENT:
                {
                    UART_PutChar(TERM_PORT,m_MCU_Info.Version);
                    UART_PutChar(TERM_PORT,m_MCU_Info.Sdid>>8);
                    UART_PutChar(TERM_PORT,m_MCU_Info.Sdid);

                    pTempAddress = (ADDRESS_TYPE *)&m_MCU_Info.BlocksCnt;
                    for(i=0; i<7; i++)
                    {
                        UART_PutChar(TERM_PORT,pTempAddress[i].Bytes.hh);
                        UART_PutChar(TERM_PORT,pTempAddress[i].Bytes.hl);
                        UART_PutChar(TERM_PORT,pTempAddress[i].Bytes.lh);
                        UART_PutChar(TERM_PORT,pTempAddress[i].Bytes.ll);
                    }
                    i = 0;
                    do
                    {
                        UART_PutChar(TERM_PORT,m_MCU_Info.IdString[i]);
                    }
                    while(m_MCU_Info.IdString[i++]);

                }
                break;
                case FC_CMD_ERASE:
                {
                    g_ucFC_State = FC_STATE_EREASE;
                }
                break;
                case FC_CMD_WRITE:
                {
                    g_ucFC_State = FC_STATE_WRITE_ADDRESS;
                }
                break;
                case FC_CMD_READ:
                {
                    g_ucFC_State = FC_STATE_READ;
                }
                break;
                case FC_CMD_QUIT:
                {
                    SCB_VTOR = RELOCATION_VERTOR_ADDR;
                    JumpToUserApplication(RELOCATION_VERTOR_ADDR);
                }
                break;
                default:
                    break;
            }
            m_uiRecCount = 0;
        }
        break;

        case FC_STATE_EREASE:
        {
            m_pRecFrame[m_uiRecCount++] = uiReadData;
            if(m_uiRecCount >= sizeof(u32))
            {
                // erase
                LONG_Convert(&m_RecFrame.uiAddress);
                if(!FLASH_EraseSector(m_RecFrame.uiAddress))
                {
                    UART_PutChar(TERM_PORT,FC_CMD_ACK);
                }
                else
                {
                    UART_PutChar(TERM_PORT,FC_CMD_NACK);
                }

                g_ucFC_State = FC_STATE_WORKING;
            }
        }
        break;
        case FC_STATE_WRITE_ADDRESS:
        {
            m_pRecFrame[m_uiRecCount++] = uiReadData;
            if(m_uiRecCount >= sizeof(u32))
            {
                g_ucFC_State = FC_STATE_WRITE_LEN;
            }

        }
        break;
        case FC_STATE_WRITE_LEN:
        {
            m_pRecFrame[m_uiRecCount++] = uiReadData;
            g_ucFC_State = FC_STATE_WRITE_DATA;
        }
        break;
        case FC_STATE_WRITE_DATA:
        {
            m_pRecFrame[m_uiRecCount++] = uiReadData;
            if(m_uiRecCount > (m_RecFrame.Length + sizeof(u32)))
            {
                LONG_Convert(&m_RecFrame.uiAddress);
                Memcpy_Byte((u8 *)&m_ucDataBuff[0],(u8 *)&m_RecFrame.DataBuff[0],m_RecFrame.Length);
                uiNumberCount ++;

                if(!FLASH_Program(m_RecFrame.uiAddress,
                                  (u8 *)&m_ucDataBuff[0],m_RecFrame.Length))
                {
                    UART_PutChar(TERM_PORT,FC_CMD_ACK);
                }
                else
                {
                    UART_PutChar(TERM_PORT,FC_CMD_NACK);
                }

                g_ucFC_State = FC_STATE_WORKING;
            }
        }
        break;
        case FC_STATE_READ:
        {
            m_pRecFrame[m_uiRecCount++] = uiReadData;
            if(m_uiRecCount > sizeof(u32))
            {
                LONG_Convert(&m_RecFrame.uiAddress);
                pAddress = (u8 *)m_RecFrame.uiAddress;
                for(i=0; i<m_RecFrame.Length; i++)
                {
                    UART_PutChar(TERM_PORT,pAddress[i]);
                }
                g_ucFC_State = FC_STATE_WORKING;
            }
        }
        break;
        default:
            break;
    }
    return 1;
}


void JumpToUserApplication(u32 userStartup)
{
//    /* set up stack pointer */
//    asm("LDR     r1, [r0]");
//    asm("mov     r13, r1");
//    /* jump to application reset vector */
//    asm("ADDS      r0,r0,#0x04 ");
//    asm("LDR      r0, [r0]");
//    asm("BX       r0");
    void (*AppReset)(void);

    AppReset = (void (*)(void))(*((uint32_t *)(userStartup + 4)));
    AppReset();
}

void LONG_Convert(u32 *pLong)
{
    unsigned char *p;
    unsigned char ucTemp;
    p = (unsigned char *)pLong;
    ucTemp = p[0];
    p[0]   = p[3];
    p[3]   = ucTemp;
    ucTemp = p[1];
    p[1]   = p[2];
    p[2]   = ucTemp;
}

void Memcpy_Byte(u8 * Dest,u8 * Src,u32 Size)
{
    while(Size--)
    {
        *Dest++ = *Src++;
    }
}
#if 0
u16 Flash_Write(u32 wNVMTargetAddress, u8 *pData, u16 sizeBytes)
{
    u16 err            = FLASH_ERR_SUCCESS;
    u8  wLeftBytes     = (sizeBytes & 0x03);
    u16 wLeftLongWords = sizeBytes>>2;
    u32 wTargetAddress = wNVMTargetAddress;
    u32 dwData0,dwData1;
    u32 *pdwData       = (u32*)pData;
    int  i;

    // Check address to see if it is aligned to 4 bytes
    // Global address [1:0] must be 00.
    if(wNVMTargetAddress & 0x03)
    {
        err = FLASH_ERR_INVALID_PARAM;
        return (err);
    }
    for(i = 0; i < wLeftLongWords; i++)
    {
        dwData0 = *pdwData++;
        err = FLASH_Program1LongWord(wTargetAddress, dwData0);
        if(err)
        {
            goto EndP;
            //break;
        }
        wTargetAddress += 4;
    }

    if(!wLeftBytes)
    {
        return (err);
    }

#if     defined(BIG_ENDIAN)
    dwData0 = 0;
    pData = (u8*)pdwData;  // pointer to the left bytes
    for(i = wLeftBytes; i >0; i--)
    {
        dwData0 <<= 8;
        dwData0 |= *pData++;    // MSB byte first
    }
    // Calculate how many bytes need to be filled with 0xFFs
    // in order to form a single longword for the left bytes of data
    wLeftBytes = 4 - wLeftBytes;
    //
    for(i = wLeftBytes; i >0; i--)
    {
        dwData0 <<= 8;
        dwData0 |= 0xFF;    // MSB byte first
    }
#else
    dwData0 = 0xFFFFFFFFL;
    pData = (u8*)pdwData+wLeftBytes-1; // pointer to the left bytes
    for(i = wLeftBytes; i >0; i--)
    {
        dwData0 <<= 8;
        dwData0 |= *pData--;    // MSB byte first
    }
#endif
    // Now program the last longword
    err = FLASH_Program1LongWord(wTargetAddress, dwData0);
EndP:
    return (err);

}
#endif
